#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <mqtt/async_client.h>

const std::string SERVER_ADDRESS("tcp://localhost:1883");
const std::string CLIENT_ID("paho_cpp_async");
const std::string TOPIC("test");

class callback : public virtual mqtt::callback, public virtual mqtt::iaction_listener
{
private:
    mqtt::async_client &client_;

public:
    callback(mqtt::async_client &client) : client_(client) {}

    void connection_lost(const std::string &cause) override
    {
        std::cout << "\nConnection lost" << std::endl;
        if (!cause.empty())
            std::cout << "\tcause: " << cause << std::endl;
    }

    void delivery_complete(mqtt::delivery_token_ptr token) override {}

    void message_arrived(const mqtt::const_message_ptr msg) override
    {
        std::cout << "Message arrived: " << msg->get_payload_str() << std::endl;
    }

    void on_failure(const mqtt::token &tok) override
    {
        std::cout << "Connection attempt failed" << std::endl;
    }

    void on_success(const mqtt::token &tok) override
    {
        std::cout << "Connection attempt successful" << std::endl;

        // 发布消息
        mqtt::message_ptr pubmsg = mqtt::make_message(TOPIC, "Hello from Paho C++");
        pubmsg->set_qos(1);
        client_.publish(pubmsg);
    }
};

int main(int argc, char *argv[])
{
    mqtt::async_client client(SERVER_ADDRESS, CLIENT_ID);

    callback cb(client);
    client.set_callback(cb);

    mqtt::connect_options connOpts;
    connOpts.set_clean_session(true);

    try
    {
        std::cout << "Connecting to the MQTT server..." << std::endl;
        mqtt::token_ptr conntok = client.connect(connOpts);
        conntok->wait();

        std::cout << "Connected!" << std::endl;

        // 订阅消息
        client.subscribe(TOPIC, 1);

        while (true)
        {
            // 持续监听消息
            usleep(1000000);
        }
    }
    catch (const mqtt::exception &exc)
    {
        std::cerr << "Error: " << exc.what() << std::endl;
        return 1;
    }

    return 0;
}
